﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CRMAdminDashboard.CrmSvc;
using System.Windows.Forms;
using System.IO;
using System.Xml.Serialization;
using System.Collections;

namespace CRMAdminDashboard
{
    /// <summary>
    /// Code behind FormAssignRoles
    /// </summary>
    public class HelperAssignRoles : HelperBase
    {

        #region Constants

        private const string RES_ASSIGNFORM_CROSSBU = "RES_ASSIGNFORM_CROSSBU";
        private const string RES_ASSIGNFORM_CROSSBU_TITLE = "RES_ASSIGNFORM_CROSSBU_TITLE";
        private const string RES_ASSIGNFORM_ADDCONFIRM1 = "RES_ASSIGNFORM_ADDCONFIRM1";
        private const string RES_ASSIGNFORM_ADDCONFIRM2 = "RES_ASSIGNFORM_ADDCONFIRM2";
        private const string RES_ASSIGNFORM_ADDCONFIRM3 = "RES_ASSIGNFORM_ADDCONFIRM3";
        private const string RES_ASSIGNFORM_ADDCONFIRM_TITLE = "RES_ASSIGNFORM_ADDCONFIRM_TITLE";
        private const string RES_ASSIGNFORM_REMOVECONFIRM1 = "RES_ASSIGNFORM_REMOVECONFIRM1";
        private const string RES_ASSIGNFORM_REMOVECONFIRM2 = "RES_ASSIGNFORM_REMOVECONFIRM2";
        private const string RES_ASSIGNFORM_REMOVECONFIRM3 = "RES_ASSIGNFORM_REMOVECONFIRM3";
        private const string RES_ASSIGNFORM_REMOVECONFIRM_TITLE = "RES_ASSIGNFORM_REMOVECONFIRM_TITLE";
        private const string RES_ASSIGNFORM_REMOVELAST = "RES_ASSIGNFORM_REMOVELAST";
        private const string RES_ASSIGNFORM_REMOVELAST_TITLE = "RES_ASSIGNFORM_REMOVELAST_TITLE";
        private const string RES_ASSIGNFORM_SELECTBYUSER = "RES_ASSIGNFORM_SELECTBYUSER";
        private const string RES_ASSIGNFORM_MAKELIKECONFIRM1 = "RES_ASSIGNFORM_MAKELIKECONFIRM1";
        private const string RES_ASSIGNFORM_MAKELIKECONFIRM2 = "RES_ASSIGNFORM_MAKELIKECONFIRM2";
        private const string RES_ASSIGNFORM_MAKELIKECONFIRM3 = "RES_ASSIGNFORM_MAKELIKECONFIRM3";
        private const string RES_ASSIGNFORM_MAKELIKECONFIRM_TITLE = "RES_ASSIGNFORM_MAKELIKECONFIRM_TITLE";

        #endregion

        #region Fields

        /// <summary>
        /// The CRM Service handle
        /// </summary>
        private CachingCrmService _svcHandle;

        /// <summary>
        /// Relationship between roles
        /// </summary>
        private RoleUserHierarchy _rUHierarchy;

        #endregion

        #region Properties

        /// <summary>
        /// BuFilter is persisted in RoleUserHierarchy
        /// </summary>
        public Dictionary<Guid, BusinessUnit> BuFilter
        {
            get
            {
                return RUHierarchy.BuFilter;
            }
        }

        /// <summary>
        /// Relationship between roles
        /// </summary>
        public RoleUserHierarchy RUHierarchy
        {
            get
            {
                if (_rUHierarchy == null)
                {
                    _rUHierarchy = new RoleUserHierarchy(_svcHandle);
                }
                return _rUHierarchy;
            }
        }

        #endregion

        #region Entry Points

        /// <summary>
        /// Standard ctor.
        /// </summary>
        public HelperAssignRoles(CachingCrmService svcHandle)
        {
            this._svcHandle = svcHandle;
        }

        /// <summary>
        /// Get all user and all roles and populate the list boxes
        /// </summary>
        public void GetUsersRoles(ListBox lstUsers, ListBox lstRoles)
        {
            lstUsers.SelectedIndex = -1;
            lstUsers.Items.Clear();
            lstRoles.SelectedIndex = -1;
            lstRoles.Items.Clear();
            this.RUHierarchy.Clear();
            this._svcHandle.InvalidateCache();

            try
            {
                // get the BUs
                FormSelectBUs dialog = new FormSelectBUs(_svcHandle);
                dialog.BuFilter = RUHierarchy.BuFilter;
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    this.RUHierarchy.BuFilter = dialog.BuFilter;

                    // users
                    foreach (SystemUser su in this.RUHierarchy.FilteredUsers.Values)
                    {
                        lstUsers.Items.Add(su);
                    }

                    // roles
                    foreach (SystemRole rl in this.RUHierarchy.FilteredRoles.Values)
                    {
                        lstRoles.Items.Add(rl);
                    }
                }
            }
            catch (Exception ex)
            {
                FormAssignRoles.WriteLog(true, ex);
            }
        }

        /// <summary>
        /// Save all roles per user as XML file
        /// </summary>
        public void DumpUsersRoles()
        {
            try
            {
                // get users with *all* their columns
                Dictionary<Guid, SystemUser> allUsers = SystemUser.GetAllUsers(_svcHandle, new AllColumns());

                // make the users serializable, but only if they are included in the filter
                List<SerializableUser> allSerializableUsers = new List<SerializableUser>();
                foreach (SystemUser su in allUsers.Values)
                {
                    if (RUHierarchy.FilteredUsers.ContainsKey(su.Id))
                    {
                        allSerializableUsers.Add(new SerializableUser(_svcHandle, su));
                    }
                }

                XmlSerializer serializer = new XmlSerializer(typeof(List<SerializableUser>));
                string fileName;
                this.SaveXmlFile(serializer, allSerializableUsers, out fileName);
                FormAssignRoles.WriteLog(true, string.Format("File [{0}] saved successfully." + Environment.NewLine, fileName));
            }
            catch (Exception ex)
            {
                FormAssignRoles.WriteLog(true, ex);
            }
        }

        /// <summary>
        /// Save all users per role as XML file
        /// </summary>
        public void DumpRolesUsers()
        {
            try
            {
                // get roles with *all* their columns
                Dictionary<Guid, SystemRole> allRoles = SystemRole.GetAllRoles(_svcHandle, null, new AllColumns());

                // make the roles serializable, but only under condition
                List<SerializableRole> allSerializableRoles = new List<SerializableRole>();
                foreach (SystemRole sr in allRoles.Values)
                {
                    SerializableRole role = new SerializableRole(_svcHandle, sr, RUHierarchy);
                    if (RUHierarchy.BuFilter == null)
                    {
                        // serialize if it has users
                        if (role.Users.Count > 0)
                        {
                            allSerializableRoles.Add(role);
                        }
                    }
                    else
                    {
                        // serialize if it has users and its BU is in the filter
                        if (role.Users.Count > 0 && RUHierarchy.BuFilter.ContainsKey(sr.BusinessUnitId))
                        {
                            allSerializableRoles.Add(role);
                        }
                    }
                }

                XmlSerializer serializer = new XmlSerializer(typeof(List<SerializableRole>));
                string fileName;
                this.SaveXmlFile(serializer, allSerializableRoles, out fileName);
                FormAssignRoles.WriteLog(true, string.Format("File [{0}] saved successfully." + Environment.NewLine, fileName));
            }
            catch (Exception ex)
            {
                FormAssignRoles.WriteLog(true, ex);
            }
        }

        /// <summary>
        /// Select all roles owned by a user set
        /// </summary>
        /// <param name="mode">0 -> All roles (Union); 1 -> At least roles (Intersection)</param>
        public void SelectRolesByUsers(IEnumerable<SystemUser> selectedUsers, ListBox lstRoles, int mode)
        {
            try
            {
                lstRoles.ClearSelected();
                Dictionary<Guid, SystemRole> selectedRoles = null;

                if (mode == 0)
                {
                    // union
                    foreach (SystemUser user in selectedUsers)
                    {
                        selectedRoles = RolesUnion(selectedRoles, user);
                    }
                }
                else
                {
                    // intersection
                    foreach (SystemUser user in selectedUsers)
                    {
                        selectedRoles = RolesIntersection(selectedRoles, user);
                    }
                }

                // select the roles in the listBox
                for (int idx = 0; idx < lstRoles.Items.Count; idx++)
                {
                    SystemRole listRole = (SystemRole)lstRoles.Items[idx];
                    foreach (Guid selectedId in selectedRoles.Keys)
                    {
                        if (listRole.Id.Equals(selectedId))
                        {
                            lstRoles.SetSelected(idx, true);
                            break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                FormAssignRoles.WriteLog(true, ex);
            }
        }

        /// <summary>
        /// Select all users owning a role set
        /// </summary>
        /// <param name="mode">0 -> All users (Union); 1 -> At least users (Intersection)</param>
        public void SelectUsersByRoles(IEnumerable<SystemRole> selectedRoles, ListBox lstUsers, int mode)
        {
            try
            {
                lstUsers.ClearSelected();
                Dictionary<Guid, SystemUser> selectedUsers = null;

                if (mode == 0)
                {
                    // union
                    foreach (SystemRole role in selectedRoles)
                    {
                        selectedUsers = UsersUnion(selectedUsers, role);
                    }
                }
                else
                {
                    // intersection
                    foreach (SystemRole role in selectedRoles)
                    {
                        selectedUsers = UsersIntersection(selectedUsers, role);
                    }
                }

                // select the users in the listBox
                for (int idx = 0; idx < lstUsers.Items.Count; idx++)
                {
                    SystemUser user = (SystemUser)lstUsers.Items[idx];
                    foreach (Guid selectedId in selectedUsers.Keys)
                    {
                        if (user.Id.Equals(selectedId))
                        {
                            lstUsers.SetSelected(idx, true);
                            break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                FormAssignRoles.WriteLog(true, ex);
            }
        }

        /// <summary>
        /// Add all the selectedRoles to the selectedUsers (unless they already have them)
        /// </summary>
        /// <param name="topLevel">true if this method is called through the GUI.
        /// Otherwise the method is called from some other top level method</param>
        public int AddRoles(IEnumerable<SystemUser> selectedUsers, IEnumerable<SystemRole> selectedRoles, bool topLevel)
        {
            int added = 0;
            try
            {
                if (topLevel)
                {
                    // check and confirm
                    if (!RolesCheck(selectedUsers, selectedRoles))
                    {
                        return 0;
                    }
                    if (!OperationConfirm(selectedUsers, selectedRoles,
                        RES_ASSIGNFORM_ADDCONFIRM1,
                        RES_ASSIGNFORM_ADDCONFIRM2,
                        RES_ASSIGNFORM_ADDCONFIRM3,
                        RES_ASSIGNFORM_ADDCONFIRM_TITLE))
                    {
                        return 0;
                    }
                }

                foreach (SystemUser user in selectedUsers)
                {
                    Dictionary<Guid, SystemRole> userRoles = user.GetRoles(_svcHandle, SystemRole.SystemRoleColumnSet);
                    foreach (SystemRole role in selectedRoles)
                    {
                        // find the actual role (its BU must match the user's)
                        SystemRole buRole = role.FindRoleByBU(user.BusinessUnitId);
                        if (buRole == null)
                        {
                            throw new ApplicationException("Role " + this.ToString() + " cannot be found");
                        }
                        if (AddRole(user, userRoles, buRole))
                        {
                            added++;
                        }
                    }
                }

                if (topLevel)
                {
                    FormAssignRoles.WriteLog(true, string.Format("{0} users selected,", selectedUsers.Count<SystemUser>()));
                    FormAssignRoles.WriteLog(true, string.Format(" {0} roles selected,", selectedRoles.Count<SystemRole>()));
                    FormAssignRoles.WriteLog(true, string.Format(" {0} roles added." + Environment.NewLine + Environment.NewLine, added));

                    // we clear hierarchy, so it will be recalculated next time it is used.
                    RUHierarchy.Clear();
                }

                return added;
            }
            catch (Exception ex)
            {
                FormAssignRoles.WriteLog(true, ex);
                return 0;
            }
        }

        /// <summary>
        /// Remove all the selectedRoles to the selectedUsers (if they have them)
        /// </summary>
        /// <param name="topLevel">true if this method is called through the GUI.
        /// Otherwise the method is called from some other top level method</param>
        public int RemoveRoles(IEnumerable<SystemUser> selectedUsers, IEnumerable<SystemRole> selectedRoles, bool topLevel)
        {
            int removed = 0;
            try
            {
                if (topLevel)
                {
                    // we don't allow tampering with the current user
                    WhoAmIResponse response = (WhoAmIResponse)_svcHandle.Execute(new WhoAmIRequest());
                    foreach (SystemUser user in selectedUsers)
                    {
                        if (response.UserId.Equals(user.Id))
                        {
                            MessageBox.Show("Cannot remove roles from the current user.", "Error",
                                MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return 0;
                        }
                    }

                    // confirm
                    if (!OperationConfirm(selectedUsers, selectedRoles,
                        RES_ASSIGNFORM_REMOVECONFIRM1,
                        RES_ASSIGNFORM_REMOVECONFIRM2,
                        RES_ASSIGNFORM_REMOVECONFIRM3,
                        RES_ASSIGNFORM_REMOVECONFIRM_TITLE))
                    {
                        return 0;
                    }
                }

                foreach (SystemUser user in selectedUsers)
                {
                    Dictionary<Guid, SystemRole> userRoles = user.GetRoles(_svcHandle, SystemRole.SystemRoleColumnSet);
                    foreach (SystemRole role in selectedRoles)
                    {
                        // find the actual role (its BU must match the user's)
                        SystemRole buRole = role.FindRoleByBU(user.BusinessUnitId);
                        if (buRole != null)
                        {
                            if (RemoveRole(user, userRoles, buRole, topLevel))
                            {
                                removed++;
                            }
                        }
                    }
                }

                if (topLevel)
                {
                    FormAssignRoles.WriteLog(true, string.Format("{0} users selected,", selectedUsers.Count<SystemUser>()));
                    FormAssignRoles.WriteLog(true, string.Format(" {0} roles selected,", selectedRoles.Count<SystemRole>()));
                    FormAssignRoles.WriteLog(true, string.Format(" {0} role assignments removed." + Environment.NewLine + Environment.NewLine, removed));

                    // we clear hierarchy, so it will be recalculated next time it is used.
                    RUHierarchy.Clear();
                }

                return removed;
            }
            catch (Exception ex)
            {
                FormAssignRoles.WriteLog(true, ex);
                return 0;
            }
        }

        /// <summary>
        /// Pick a user and assign all and only its roles to all the users selected.
        /// </summary>
        /// <param name="lstUsers"></param>
        /// <param name="lstRoles"></param>
        public void MakeLike(IEnumerable<SystemUser> selectedUsers, ListBox lstRoles)
        {
            try
            {
                // we don't allow tampering with the current user
                WhoAmIResponse response = (WhoAmIResponse)_svcHandle.Execute(new WhoAmIRequest());
                foreach (SystemUser user in selectedUsers)
                {
                    if (response.UserId.Equals(user.Id))
                    {
                        MessageBox.Show("Cannot use this command on the current user. Please remove yourself from the selected users' list.", "Error",
                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                }

                // select template user
                FormSelectByUser dialog = new FormSelectByUser(Program.GetResString(RES_ASSIGNFORM_SELECTBYUSER), RUHierarchy);
                if (dialog.ShowDialog() != DialogResult.OK)
                {
                    return;
                }
                SystemUser templateUser = dialog.SelectedUser;

                // can't make like self
                foreach (SystemUser user in selectedUsers)
                {
                    if (user.Id.Equals(templateUser.Id))
                    {
                        MessageBox.Show(
                            string.Format("Cannot use this command on the template user." + Environment.NewLine + Environment.NewLine +
                            "Please remove the template user ({0}) from the selected users' list.",
                            templateUser.ToStringShort()), "Error",
                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                }

                // select roles owned by the template user
                this.SelectRolesByUsers(new SystemUser[] { templateUser }, lstRoles, 0);

                // collect selected roles
                Dictionary<Guid, SystemRole> selRoles = new Dictionary<Guid, SystemRole>();
                foreach (SystemRole role in lstRoles.SelectedItems.Cast<SystemRole>())
                {
                    selRoles.Add(role.Id, role);
                }

                // check that we have roles to assign
                if (selRoles.Keys.Count == 0)
                {
                    MessageBox.Show(
                        string.Format("The template user ({0}) has no roles assigned.", templateUser.ToStringShort()), "Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                // check that we can assign all the roles to all the users selected
                if (!RolesCheck(selectedUsers, selRoles.Values))
                {
                    return;
                }

                // confirm
                if (!OperationConfirm(selectedUsers, selRoles.Values,
                    RES_ASSIGNFORM_MAKELIKECONFIRM1,
                    RES_ASSIGNFORM_MAKELIKECONFIRM2,
                    RES_ASSIGNFORM_MAKELIKECONFIRM3,
                    RES_ASSIGNFORM_MAKELIKECONFIRM_TITLE))
                {
                    return;
                }

                // add all roles
                int added = AddRoles(selectedUsers, selRoles.Values, false);

                // toggle selection of roles
                for (int idx = 0; idx < lstRoles.Items.Count; idx++)
                {
                    lstRoles.SetSelected(idx, !lstRoles.GetSelected(idx));
                }

                // remove superflous roles
                int removed = RemoveRoles(selectedUsers, lstRoles.SelectedItems.Cast<SystemRole>(), false);

                // clear selection
                for (int idx = 0; idx < lstRoles.Items.Count; idx++)
                {
                    lstRoles.SetSelected(idx, false);
                }

                FormAssignRoles.WriteLog(true, string.Format("{0} users selected,", selectedUsers.Count<SystemUser>()));
                FormAssignRoles.WriteLog(true, string.Format(" {0} roles selected,", selRoles.Keys.Count));
                FormAssignRoles.WriteLog(true, string.Format(" {0} roles added," + Environment.NewLine + Environment.NewLine, added));
                FormAssignRoles.WriteLog(true, string.Format(" {0} role assignments removed." + Environment.NewLine + Environment.NewLine, removed));

                // we clear hierarchy, so it will be recalculated next time it is used.
                RUHierarchy.Clear();
            }
            catch (Exception ex)
            {
                FormAssignRoles.WriteLog(true, ex);
            }
        }

        #endregion

        #region Local Methods

        /// <summary>
        /// Return a UNION betwen selectRoles and the (root) roles owned by user
        /// </summary>
        /// <param name="selectRoles">set of roles</param>
        /// <param name="user">the user that owns roles to be added to the set</param>
        /// <returns>new set of roles</returns>
        private Dictionary<Guid, SystemRole> RolesUnion(Dictionary<Guid, SystemRole> selectRoles, SystemUser user)
        {
            Dictionary<Guid, SystemRole> roles = user.GetRootRoles(_svcHandle, this.RUHierarchy);
            if (selectRoles == null)
            {
                selectRoles = new Dictionary<Guid, SystemRole>();
            }

            // for each role, add them to the set if not already there
            foreach (SystemRole role in roles.Values)
            {
                if (!selectRoles.ContainsKey(role.Id))
                {
                    selectRoles.Add(role.Id, role);
                }
            }

            return selectRoles;
        }

        /// <summary>
        /// Return an INTERSECTION betwen selectRoles and the (root) roles owned by user
        /// </summary>
        /// <param name="selectRoles">set of roles</param>
        /// <param name="user">the user that owns roles to be added to the set</param>
        /// <returns>new set of roles</returns>
        private Dictionary<Guid, SystemRole> RolesIntersection(Dictionary<Guid, SystemRole> selectRoles, SystemUser user)
        {
            Dictionary<Guid, SystemRole> roles = user.GetRootRoles(_svcHandle, this.RUHierarchy);

            if (selectRoles == null)
            {
                // this is the first user: add all its roles to the collection
                selectRoles = new Dictionary<Guid, SystemRole>();
                foreach (SystemRole role in roles.Values)
                {
                    selectRoles.Add(role.Id, role);
                }
            }
            else
            {
                // check that the collection contains only roles owned by the user, if not remove them
                Dictionary<Guid, SystemRole> selectRolesCopy = new Dictionary<Guid, SystemRole>(selectRoles);
                foreach (Guid roleid in selectRolesCopy.Keys)
                {
                    if (!roles.ContainsKey(roleid))
                    {
                        // we need to remove this role
                        selectRoles.Remove(roleid);
                    }
                }
            }

            return selectRoles;
        }

        /// <summary>
        /// Return a UNION betwen selectUsers and the users who own this role or any of the derived roles
        /// </summary>
        /// <param name="selectUsers">set of users</param>
        /// <param name="role">the role that users to be added to the set own</param>
        /// <returns>new set of users</returns>
        private Dictionary<Guid, SystemUser> UsersUnion(Dictionary<Guid, SystemUser> selectUsers, SystemRole role)
        {
            Dictionary<Guid, SystemUser> users = role.GetUsersDeep(_svcHandle, RUHierarchy);
            if (selectUsers == null)
            {
                selectUsers = new Dictionary<Guid, SystemUser>();
            }

            foreach (SystemUser user in users.Values)
            {
                // for each user, add them to collection if not already there
                if (!selectUsers.ContainsKey(user.Id))
                {
                    selectUsers.Add(user.Id, user);
                }
            }

            return selectUsers;
        }

        /// <summary>
        /// Return an INTERSECTION betwen selectUsers and the users who own this role or any of the derived roles
        /// </summary>
        /// <param name="selectUsers">set of users</param>
        /// <param name="role">the role that users to be added to the set own</param>
        /// <returns>new set of users</returns>
        private Dictionary<Guid, SystemUser> UsersIntersection(Dictionary<Guid, SystemUser> selectUsers, SystemRole role)
        {
            Dictionary<Guid, SystemUser> users = role.GetUsersDeep(_svcHandle, RUHierarchy);
            if (selectUsers == null)
            {
                // this is the first role: add all its users to the collection
                selectUsers = new Dictionary<Guid, SystemUser>(users);
            }
            else
            {
                // check that the collection contains only users who own the role, if not remove them
                Dictionary<Guid, SystemUser> selectUsersCopy = new Dictionary<Guid, SystemUser>(selectUsers);
                foreach (SystemUser user in selectUsersCopy.Values)
                {
                    if (!users.ContainsKey(user.Id))
                    {
                        // we need to remove this user
                        selectUsers.Remove(user.Id);
                    }
                }
            }

            return selectUsers;
        }

        /// <summary>
        /// Check whether all the roles can be added/removed to all the users
        /// </summary>
        private bool RolesCheck(IEnumerable<SystemUser> selectedUsers, IEnumerable<SystemRole> selectedRoles)
        {
            foreach (SystemUser user in selectedUsers)
            {
                Guid UserBU = user.BusinessUnitId;
                foreach (SystemRole role in selectedRoles)
                {
                    if (!role.DerivedBUs.Contains(UserBU))
                    {
                        MessageBox.Show(
                            string.Format(Program.GetResString(RES_ASSIGNFORM_CROSSBU), role.ToString(), user.ToString(),
                            user.BusinessUnitName),
                            Program.GetResString(RES_ASSIGNFORM_CROSSBU_TITLE),
                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return false;
                    }
                }
            }

            return true;
        }

        /// <summary>
        /// Add a role to a user, if it's not already owned.
        /// </summary>
        /// <param name="userRoles">user's owned roles</param>
        /// <param name="role">role to add</param>
        private bool AddRole(SystemUser user, Dictionary<Guid, SystemRole> userRoles, SystemRole role)
        {
            if (userRoles.ContainsKey(role.Id))
            {
                FormAssignRoles.WriteLog(false, string.Format("User \"{0}\" already owns role \"{1}\"." + Environment.NewLine,
                    user.ToStringShort(), role.ToString()));
                return false;
            }

            AssignUserRolesRoleRequest request = new AssignUserRolesRoleRequest();
            request.UserId = user.Id;
            request.RoleIds = new Guid[] { role.Id };
            AssignUserRolesRoleResponse response = (AssignUserRolesRoleResponse)_svcHandle.Execute(request);
            FormAssignRoles.WriteLog(false, string.Format("Role \"{0}\" assigned to user \"{1}\"." + Environment.NewLine,
                role.ToString(), user.ToStringShort()));

            return true;
        }

        /// <summary>
        /// Remove a role from a user, if it's owned.
        /// </summary>
        /// <param name="userRoles">user's owned roles. this collection will be modified if the removal was successful</param>
        /// <param name="role">role to remove</param>
        /// <param name="topLevel">true if this method is called through the GUI.
        /// Otherwise the method is called from some other top level method</param>
        private bool RemoveRole(SystemUser user, Dictionary<Guid, SystemRole> userRoles, SystemRole role, bool topLevel)
        {
            if (topLevel)
            {
                if (!userRoles.ContainsKey(role.Id))
                {
                    FormAssignRoles.WriteLog(false, string.Format("User \"{0}\" does not own role \"{1}\"." + Environment.NewLine,
                        user.ToStringShort(), role.ToString()));
                    return false;
                }

                if (userRoles.Count == 1)
                {
                    // do we want to remove the last role?
                    DialogResult dialogResponse = MessageBox.Show(
                        string.Format(Program.GetResString(RES_ASSIGNFORM_REMOVELAST), user.ToString()),
                        Program.GetResString(RES_ASSIGNFORM_REMOVELAST_TITLE),
                        MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                    if (dialogResponse == DialogResult.No)
                    {
                        return false;
                    }
                    else if (dialogResponse == DialogResult.Cancel)
                    {
                        throw new ApplicationException("Operation aborted.");
                    }
                }
            }

            RemoveUserRolesRoleRequest request = new RemoveUserRolesRoleRequest();
            request.UserId = user.Id;
            request.RoleIds = new Guid[] { role.Id };
            RemoveUserRolesRoleResponse response = (RemoveUserRolesRoleResponse)_svcHandle.Execute(request);
            FormAssignRoles.WriteLog(false, string.Format("Role \"{0}\" removed from user \"{1}\"." + Environment.NewLine,
                role.ToString(), user.ToStringShort()));

            userRoles.Remove(role.Id);

            return true;
        }

        /// <summary>
        /// Confirm whether the operation can be carried out
        /// </summary>
        private bool OperationConfirm(IEnumerable<SystemUser> selectedUsers,
            IEnumerable<SystemRole> selectedRoles,
            string res1, string res2, string res3, string res4)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(Program.GetResString(res1));
            sb.AppendLine();
            foreach (SystemRole sr in selectedRoles)
            {
                sb.AppendLine("\t" + sr.ToString());
            }
            sb.AppendLine();
            sb.AppendLine(Program.GetResString(res2));
            sb.AppendLine();
            foreach (SystemUser su in selectedUsers)
            {
                sb.AppendLine("\t" + su.FullName);
            }
            sb.AppendLine();
            sb.AppendLine(Program.GetResString(res3));

            if (MessageBox.Show(sb.ToString(), Program.GetResString(res4),
                MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                return true;
            }

            return false;
        }

        #endregion

    }
}
